package com.easylinkin.linkappapi.powerdistribution.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.additional.update.impl.LambdaUpdateChainWrapper;
import com.easylinkin.linkappapi.alarm.constant.AlarmConstant;
import com.easylinkin.linkappapi.alarm.entity.*;
import com.easylinkin.linkappapi.alarm.mapper.AlarmNoticeTempletMapper;
import com.easylinkin.linkappapi.alarm.service.AlarmProcessService;
import com.easylinkin.linkappapi.alarm.service.AlarmService;
import com.easylinkin.linkappapi.common.constant.CommonConstant;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.DateUtil;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.device.mapper.DeviceMapper;
import com.easylinkin.linkappapi.deviceattributestatus.entity.DeviceAttributeStatus;
import com.easylinkin.linkappapi.deviceattributestatus.service.DeviceAttributeStatusService;
import com.easylinkin.linkappapi.elasticsearch.entity.BankAlarmNotice;
import com.easylinkin.linkappapi.powerdistribution.entity.DistributionCabinet;
import com.easylinkin.linkappapi.powerdistribution.entity.DistributionCabinetAlarmConfig;
import com.easylinkin.linkappapi.powerdistribution.mapper.DistributionCabinetAlarmConfigMapper;
import com.easylinkin.linkappapi.powerdistribution.mapper.DistributionCabinetMapper;
import com.easylinkin.linkappapi.powerdistribution.mapper.DistributionCompanyAlarmContactMidMapper;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.security.service.LinkappUserService;
import freemarker.cache.StringTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.MailSendException;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import java.util.List;
import java.util.stream.Collectors;

import com.easylinkin.linkappapi.powerdistribution.entity.DistributionCabinetAlarmInfo;
import com.easylinkin.linkappapi.powerdistribution.mapper.DistributionCabinetAlarmInfoMapper;
import com.easylinkin.linkappapi.powerdistribution.service.DistributionCabinetAlarmInfoService;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@Slf4j
@Service
public class DistributionCabinetAlarmInfoServiceImpl extends ServiceImpl<DistributionCabinetAlarmInfoMapper, DistributionCabinetAlarmInfo> implements DistributionCabinetAlarmInfoService {
    @Resource
    DistributionCabinetAlarmConfigMapper distributionCabinetAlarmConfigMapper;
    @Resource
    DistributionCabinetMapper distributionCabinetMapper;
    @Value("${message.signName}")
    String signName;
    @Resource
    IAcsClient acsClient;
    @Resource
    DistributionCompanyAlarmContactMidMapper distributionCompanyAlarmContactMidMapper;
    @Resource
    CommonService commonService;
    @Resource
    LinkappUserContextProducer linkappUserContextProducer;
    @Resource
    AlarmProcessService alarmProcessService;
    @Resource
    AlarmService alarmService;
    @Resource
    AlarmNoticeTempletMapper alarmNoticeTempletMapper;
    @Resource
    JavaMailSenderImpl javaMailSender;
    @Autowired
    @Qualifier("freeMarkerConfiguration")
    private Configuration freemarkerConf;
    @Resource
    DeviceMapper deviceMapper;
    @Resource
    private MimeMessageHelper mimeMessageHelper;
    private static final String PHONETEMPLETID = "12";
    private static final String EMAILTEMPLETID = "13";


    //总视在功率
    private String APPARENT_POWER = "apparent_power";
    //A、b、c相电流
    private String A_PHASE_CURRENT = "a_phase_current";
    private String B_PHASE_CURRENT = "b_phase_current";
    private String C_PHASE_CURRENT = "c_phase_current";
    //A、b、c相电压
    private String A_PHASE_VOLTAGE = "a_phase_voltage";
    private String B_PHASE_VOLTAGE = "b_phase_voltage";
    private String C_PHASE_VOLTAGE = "c_phase_voltage";

    //电压不平衡
    private String VOLTAGE_UNBALANCE_RATE="voltage_unbalance_rate";
    //电流不平衡
    private String CURRENT_UNBALANCE_RATE="current_unbalance_rate";


    @Override
    public IPage<DistributionCabinetAlarmInfo> getAlarmPage(Page page, DistributionCabinetAlarmInfo distributionCabinetAlarmInfo) {
        List<String> spacesIds = commonService.getCurrentUserSpaceIds();
        if (CollectionUtils.isEmpty(spacesIds)) {
            return page;
        }
//        租户id 过滤
        distributionCabinetAlarmInfo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        return baseMapper.findAllByCabientId(page, distributionCabinetAlarmInfo, spacesIds);
    }

    /***
     * 批量告警处理
     * @param distributionCabinetAlarmInfo
     */
    @Override
    public void  alarmProcessBatch(DistributionCabinetAlarmInfo distributionCabinetAlarmInfo){
        if(ObjectUtils.isEmpty(distributionCabinetAlarmInfo)){
            return;
        }
        Assert.notNull(distributionCabinetAlarmInfo.getAlarmStatus(), "alarmStatus 不能为空");
        LinkappUser notNullCurrent = linkappUserContextProducer.getNotNullCurrent();
        //告警
        if(distributionCabinetAlarmInfo.getAlarmIds() != null && distributionCabinetAlarmInfo.getAlarmIds().size() > 0){
            Collection<Alarm> alarmList = alarmService.listByIds(distributionCabinetAlarmInfo.getAlarmIds());
            if(alarmList == null || alarmList.size()<=0){
                return;
            }
            Map<String, String> map = alarmList.stream().collect(Collectors.toMap(Alarm::getId, Alarm::getDeviceCode, (k1, k2) -> k1));
            List<AlarmProcess> alarmProcessList = distributionCabinetAlarmInfo.getAlarmIds().stream().map(m -> {
                String devicecode = map.get(m);
                AlarmProcess alarmProcess = new AlarmProcess();
                alarmProcess.setAlarmId(m);
                alarmProcess.setDeviceCode(devicecode);
                alarmProcess.setCreator(notNullCurrent.getId()+"");
                alarmProcess.setHandlerId(notNullCurrent.getId()+"");
                return alarmProcess;
            }).collect(Collectors.toList());
            alarmProcessService.addBatch(distributionCabinetAlarmInfo.getDescription(),distributionCabinetAlarmInfo.getAlarmStatus() ,alarmProcessList);
        }
        //指标告警处理
        if(distributionCabinetAlarmInfo.getIds() != null && distributionCabinetAlarmInfo.getIds().size()>0){
            new LambdaUpdateChainWrapper<>(baseMapper)
                    .set(DistributionCabinetAlarmInfo::getDescription, distributionCabinetAlarmInfo.getDescription() )
                    .set(DistributionCabinetAlarmInfo::getAlarmStatus, distributionCabinetAlarmInfo.getAlarmStatus())
                    .set(DistributionCabinetAlarmInfo::getStatus, AlarmConstant.ProcessStatus.PROCESSED.getType())
                    .set(DistributionCabinetAlarmInfo::getDealTime, LocalDateTime.now())
                    .set(DistributionCabinetAlarmInfo::getUserId, notNullCurrent.getId()+"")
                    .in(DistributionCabinetAlarmInfo::getId,distributionCabinetAlarmInfo.getIds())
                    .update();
        }
    }

    @Override
    public Alarm getDetail(DistributionCabinetAlarmInfo distributionCabinetAlarmInfo) {
        Assert.notNull(distributionCabinetAlarmInfo,"参数不能为空" );
        List<Long> ids = distributionCabinetAlarmInfo.getIds();
        List<String> alarmIds = distributionCabinetAlarmInfo.getAlarmIds();
        if((ids == null || ids.size()<=0) &&  (alarmIds == null || alarmIds.size() <=0)){
            throw new IllegalArgumentException("ids或者alarmIds 不能为空");
        }
        if(alarmIds != null && alarmIds.size()>0){
            Alarm alarm = new Alarm();
            alarm.setId(alarmIds.get(0));
            alarm = alarmService.getDetail(alarm);
            if(alarm != null){
                alarm.setIdentificationType(1);
            }
            return alarm;
        }
        if(ids != null && ids.size()>0){
            DistributionCabinetAlarmInfo alarmInfo = new DistributionCabinetAlarmInfo();
            alarmInfo.setId(ids.get(0));
            Alarm alarm = baseMapper.getDetail(alarmInfo);
            if(alarm != null){
                alarm.setIdentificationType(2);
            }
            return alarm;
        }
        return null;
    }

    @Override
    public void exportData(DistributionCabinetAlarmInfo alarm, HttpServletRequest request, HttpServletResponse response) {
        List<String> spacesIds = commonService.getCurrentUserSpaceIds();
        if (CollectionUtils.isEmpty(spacesIds)) {
            return;
        }
//        租户id 过滤
        alarm.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        List<AlarmVo> result = baseMapper.findAllByCabientIdVos(alarm, spacesIds);
        String keyValue = "设备名称:deviceName,设备编号:deviceCode,设备类型:deviceTypeName,空间区域:deviceAreaPath,"
                + "告警规则:ruleEngineName,告警等级:level,告警内容:content,告警日志:sourceJson,告警时间:alarmTime,是否处理:processStatus,处理人:processUserName,"
                + "处理结果:processResult,是否误报:mistakeFlag,处理时间:processTime";
        String title = "设备档案告警信息导出表格";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);
            ExcelTools.exportExcel(outputStream, keyValue, result, ExcelConstant.XLS, title);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！IOException异常" + e.getMessage());
        } catch (Exception e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！" + e.getMessage());
        }

    }


    @Override
    public void triggerAlarm(Device device) {
        if (ObjectUtils.isEmpty(device)) {
            return;
        }
        List<Device> deviceList = deviceMapper.selectDevices(device);
        if(deviceList == null ||deviceList.size()<=0){
            return;
        }
        Device deviceOne = deviceList.get(0);
        device.setDeviceTypeName(deviceOne.getDeviceTypeName());
        //获取当前设备属性值
        List<DeviceAttributeStatus> latestDeviceAttributeStatusList = device.getDeviceAttributeStatusList();
        if (latestDeviceAttributeStatusList == null || latestDeviceAttributeStatusList.size() <= 0) {
            //无属性，无法计算
            return;
        }
        Map<String, String> attrMap = latestDeviceAttributeStatusList.stream().collect(Collectors.toMap(DeviceAttributeStatus::getPropCode, DeviceAttributeStatus::getPropValue, (k1, k2) -> k2));
        //总视在功率   alarmType 类型  1 负荷；3 电压；5 电流
        List<DistributionCabinetAlarmInfo> apparentPowerList = attrCalculate(APPARENT_POWER,1,attrMap, device,1);
        //电流计算
        List<DistributionCabinetAlarmInfo> currentList = attrCalculate(CURRENT_UNBALANCE_RATE,2,attrMap, device,5);
        //电压计算
        List<DistributionCabinetAlarmInfo> voltageList = attrCalculate(VOLTAGE_UNBALANCE_RATE,2,attrMap, device,3);
        ArrayList<DistributionCabinetAlarmInfo> alarmInfos = initAlarmInfoArray(apparentPowerList, currentList, voltageList);
        if(alarmInfos == null || alarmInfos.size() <= 0){
            return;
        }
        //保存
        baseMapper.batchInsert(alarmInfos);
        //发送短信处理
        sendSmsAndSaveAlarmNoticeHandler(alarmInfos);
    }



    /***
     * 创建数组
     * @param apparentPowerList
     * @param currentList
     * @param voltageList
     * @return
     */
    private ArrayList<DistributionCabinetAlarmInfo> initAlarmInfoArray(List<DistributionCabinetAlarmInfo> apparentPowerList,List<DistributionCabinetAlarmInfo> currentList,List<DistributionCabinetAlarmInfo> voltageList){
        int size=0;
        if(apparentPowerList != null){
            size+=apparentPowerList.size();
        }
        if(currentList != null){
            size+=currentList.size();
        }
        if(voltageList != null){
            size+=voltageList.size();
        }
        ArrayList<DistributionCabinetAlarmInfo> distributionCabinetAlarmInfos = new ArrayList<>(size);
        if(apparentPowerList != null){
            distributionCabinetAlarmInfos.addAll(apparentPowerList);
        }
        if(currentList != null){
            distributionCabinetAlarmInfos.addAll(currentList);
        }
        if(voltageList != null){
            distributionCabinetAlarmInfos.addAll(voltageList);
        }
        return  distributionCabinetAlarmInfos;
    }

    /***
     * 电流计算
     * @return
     */
    private List<DistributionCabinetAlarmInfo> currentCalculate(Map<String, String> attrMap, Device device) {
        String a_phase_current_str = attrMap.get(A_PHASE_CURRENT);
        String b_phase_current_str = attrMap.get(B_PHASE_CURRENT);
        String c_phase_current_str = attrMap.get(C_PHASE_CURRENT);
        if (StringUtils.isEmpty(a_phase_current_str) || StringUtils.isEmpty(b_phase_current_str) || StringUtils.isEmpty(c_phase_current_str)) {
            return null;
        }
        //计算 不平衡值
        BigDecimal phase_current = voltageOrCalculate(a_phase_current_str, b_phase_current_str, c_phase_current_str);

        DistributionCabinetAlarmConfig distributionCabinetAlarmConfig = new DistributionCabinetAlarmConfig();
        distributionCabinetAlarmConfig.setDeviceCode(device.getCode());
        distributionCabinetAlarmConfig.setQueryValue(phase_current);
        distributionCabinetAlarmConfig.setType(2);
        List<DistributionCabinetAlarmConfig> alarmConfigs = distributionCabinetAlarmConfigMapper.findAllByDeviceCode(distributionCabinetAlarmConfig);
        if (alarmConfigs == null || alarmConfigs.size() <= 0) {
            return null;
        }
        //告警参数组装
        return paramAssemble(alarmConfigs,device,phase_current,5);
    }

    /***
     * 电压计算
     * @return
     */
    private List<DistributionCabinetAlarmInfo> voltageCalculate(Map<String, String> attrMap, Device device) {
        String a_phase_current_str = attrMap.get(A_PHASE_VOLTAGE);
        String b_phase_current_str = attrMap.get(B_PHASE_VOLTAGE);
        String c_phase_current_str = attrMap.get(C_PHASE_VOLTAGE);
        if (StringUtils.isEmpty(a_phase_current_str) || StringUtils.isEmpty(b_phase_current_str) || StringUtils.isEmpty(c_phase_current_str)) {
            return null;
        }
        //计算 不平衡值
        BigDecimal phase_current = voltageOrCalculate(a_phase_current_str, b_phase_current_str, c_phase_current_str);

        DistributionCabinetAlarmConfig distributionCabinetAlarmConfig = new DistributionCabinetAlarmConfig();
        distributionCabinetAlarmConfig.setDeviceCode(device.getCode());
        distributionCabinetAlarmConfig.setQueryValue(phase_current);
        distributionCabinetAlarmConfig.setType(2);
        List<DistributionCabinetAlarmConfig> alarmConfigs = distributionCabinetAlarmConfigMapper.findAllByDeviceCode(distributionCabinetAlarmConfig);
        if (alarmConfigs == null || alarmConfigs.size() <= 0) {
            return null;
        }
        //告警参数组装
        return paramAssemble(alarmConfigs,device,phase_current,3);
    }

    /***
     * 属性值比较
     * @param attr 属性
     * @param type 1：负荷指标 2:不平衡度指标
     * @param attrMap
     * @param device
     * @param alarmType 类型  1 负荷；3 电压；5 电流
     * @return
     */
    private List<DistributionCabinetAlarmInfo> attrCalculate(String attr,Integer type,Map<String, String> attrMap, Device device,Integer alarmType){
        String apparent_power_str = attrMap.get(attr);
        if (StringUtils.isEmpty(apparent_power_str)) {
            return null;
        }
        //获取 总视在功率
        BigDecimal apparent_power = BigDecimal.valueOf(Double.valueOf(apparent_power_str));
        DistributionCabinetAlarmConfig distributionCabinetAlarmConfig = new DistributionCabinetAlarmConfig();
        distributionCabinetAlarmConfig.setDeviceCode(device.getCode());
        distributionCabinetAlarmConfig.setQueryValue(apparent_power);
        distributionCabinetAlarmConfig.setType(type);
        List<DistributionCabinetAlarmConfig> alarmConfigs = distributionCabinetAlarmConfigMapper.findAllByDeviceCode(distributionCabinetAlarmConfig);
        //告警参数组装
        return paramAssemble(alarmConfigs,device,apparent_power,alarmType);
    }

    /***
     *  总视在功率
     * @param attrMap
     * @param device
     * @return
     */
    private List<DistributionCabinetAlarmInfo> apparentPowerCalculate(Map<String, String> attrMap, Device device) {
        String apparent_power_str = attrMap.get(APPARENT_POWER);
        if (StringUtils.isEmpty(apparent_power_str)) {
            return null;
        }
        //获取 总视在功率
        BigDecimal apparent_power = BigDecimal.valueOf(Double.valueOf(apparent_power_str));
        DistributionCabinetAlarmConfig distributionCabinetAlarmConfig = new DistributionCabinetAlarmConfig();
        distributionCabinetAlarmConfig.setDeviceCode(device.getCode());
        distributionCabinetAlarmConfig.setQueryValue(apparent_power);
        distributionCabinetAlarmConfig.setType(1);
        List<DistributionCabinetAlarmConfig> alarmConfigs = distributionCabinetAlarmConfigMapper.findAllByDeviceCode(distributionCabinetAlarmConfig);
        //告警参数组装
        return paramAssemble(alarmConfigs,device,apparent_power,1);
    }

    /***
     * 组装告警信息
     * @param alarmConfigs 告警配置
     * @param device
     * @param apparent_power 告警检测值
     * @param type 类型  1 负荷；3 电压；5 电流
     * @return
     */
    private List<DistributionCabinetAlarmInfo> paramAssemble(List<DistributionCabinetAlarmConfig> alarmConfigs,Device device,BigDecimal apparent_power,int type){
        if(alarmConfigs == null || alarmConfigs.size() <= 0){
            return null;
        }
        List<DistributionCabinetAlarmConfig> apparent_power_up=new ArrayList<>();
        List<DistributionCabinetAlarmConfig> apparent_power_down=new ArrayList<>();
        if(type == 1){
            //总视在功率>=负荷指标上限  (a.compareTo(b)  -1 小于;0 等于;1 大于)
            apparent_power_up = alarmConfigs.stream().filter(m ->m.getValueMax() != null && apparent_power.compareTo(m.getValueMax()) != -1).collect(Collectors.toList());
            //总视在功率<=负荷指标下限
            apparent_power_down = alarmConfigs.stream().filter(m ->m.getValueMin() != null && apparent_power.compareTo(m.getValueMin()) != 1).collect(Collectors.toList());
        }else{
            //三相不平衡大于上限
            apparent_power_up = alarmConfigs.stream().filter(m ->m.getValueMax() != null && apparent_power.compareTo(m.getValueMax()) != -1).collect(Collectors.toList());
            ////三相不平衡大于下限
            if(apparent_power_up == null || apparent_power_up.size()<=0){
                apparent_power_down = alarmConfigs.stream().filter(m ->m.getValueMin() != null && apparent_power.compareTo(m.getValueMin()) != -1).collect(Collectors.toList());
            }
        }
        if(apparent_power_up == null){
            apparent_power_up=new ArrayList<>();
        }
        if(apparent_power_down == null){
            apparent_power_down=new ArrayList<>();
        }
        //写入告警
        //获取配电柜告警ID，一次查询
        Set<String> cabinetIds = new HashSet<>();
        if (apparent_power_up != null && apparent_power_up.size() > 0) {
            Set<String> ids = apparent_power_up.stream().map(DistributionCabinetAlarmConfig::getCabinetId).collect(Collectors.toSet());
            cabinetIds.addAll(ids);
        }
        if (apparent_power_down != null && apparent_power_down.size() > 0) {
            Set<String> ids = apparent_power_down.stream().map(DistributionCabinetAlarmConfig::getCabinetId).collect(Collectors.toSet());
            cabinetIds.addAll(ids);
        }
        if (cabinetIds == null || cabinetIds.size() <= 0) {
            return null;
        }
        DistributionCabinet distributionCabinet = new DistributionCabinet();
        distributionCabinet.setIds(cabinetIds);
        //获取所有告警配电柜
        List<DistributionCabinet> distributionCabinetList = distributionCabinetMapper.getDistributionCabinetAreaPathInfo(distributionCabinet, device);
        Map<String, DistributionCabinet> cabinetMap = distributionCabinetList.stream().collect(Collectors.toMap(DistributionCabinet::getId, m -> m, (k1, k2) -> k2));
        //参数组装
        LocalDateTime now = LocalDateTime.now();
        //上限
        List<DistributionCabinetAlarmInfo> alarmInfoUp = apparent_power_up.stream().map(m -> {
            DistributionCabinet cabinet = cabinetMap.get(m.getCabinetId());
            if(cabinet == null){
                return null;
            }
            String content = AlarmContent.getAlarmContentByType(type).content;
            if(content.indexOf("?") != -1 && m.getValueMax() != null){
                content = content.replace("?",m.getValueMax().intValue()+"");
            }
            DistributionCabinetAlarmInfo distributionCabinetAlarmInfo = new DistributionCabinetAlarmInfo();
            distributionCabinetAlarmInfo.setCabinetId(m.getCabinetId());
            distributionCabinetAlarmInfo.setDeviceCode(m.getDeviceCode());
            distributionCabinetAlarmInfo.setName(AlarmContent.getAlarmContentByType(type).name);
            distributionCabinetAlarmInfo.setContent("(" + cabinet.getSiteName() + ")" + content);
            distributionCabinetAlarmInfo.setSourceJson(device.getSourceJson());
            distributionCabinetAlarmInfo.setStatus(1);
            distributionCabinetAlarmInfo.setAlarmTime(now);
            distributionCabinetAlarmInfo.setAreaPath(cabinet.getAreaPath());
            distributionCabinetAlarmInfo.setRoomName(cabinet.getRoomName());
            distributionCabinetAlarmInfo.setCabinetName(cabinet.getName());
            distributionCabinetAlarmInfo.setCompanyId(cabinet.getCompanyId());
            distributionCabinetAlarmInfo.setLevel(1);
            distributionCabinetAlarmInfo.setDeviceTypeName(device.getDeviceTypeName());
            return distributionCabinetAlarmInfo;
        }).collect(Collectors.toList());
        //下限
        int typeDown = type + 1;
        List<DistributionCabinetAlarmInfo> alarmInfoDown = apparent_power_down.stream().map(m -> {
            DistributionCabinet cabinet = cabinetMap.get(m.getCabinetId());
            if(cabinet == null){
                return null;
            }
            String content = AlarmContent.getAlarmContentByType(typeDown).content;
            if(content.indexOf("?") != -1 && m.getValueMin() != null){
                content = content.replace("?", m.getValueMin().intValue()+"");
            }
            DistributionCabinetAlarmInfo distributionCabinetAlarmInfo = new DistributionCabinetAlarmInfo();
            distributionCabinetAlarmInfo.setCabinetId(m.getCabinetId());
            distributionCabinetAlarmInfo.setDeviceCode(m.getDeviceCode());
            distributionCabinetAlarmInfo.setName(AlarmContent.getAlarmContentByType(typeDown).name);
            distributionCabinetAlarmInfo.setContent("(" + cabinet.getSiteName() + ")" + content);
            distributionCabinetAlarmInfo.setSourceJson(device.getSourceJson());
            distributionCabinetAlarmInfo.setStatus(1);
            distributionCabinetAlarmInfo.setAlarmTime(now);
            distributionCabinetAlarmInfo.setAreaPath(cabinet.getAreaPath());
            distributionCabinetAlarmInfo.setRoomName(cabinet.getRoomName());
            distributionCabinetAlarmInfo.setCabinetName(cabinet.getName());
            distributionCabinetAlarmInfo.setCompanyId(cabinet.getCompanyId());
            distributionCabinetAlarmInfo.setLevel(1);
            distributionCabinetAlarmInfo.setDeviceTypeName(device.getDeviceTypeName());
            return distributionCabinetAlarmInfo;
        }).collect(Collectors.toList());
        alarmInfoUp.addAll(alarmInfoDown);
        return alarmInfoUp;
    }


    /***
     * 计算 不平衡值
     * @param a_phase_current_str
     * @param bPhaseCurrentStr
     * @param cPhaseCurrentStr
     * @return
     */
    private BigDecimal voltageOrCalculate(String a_phase_current_str, String bPhaseCurrentStr, String cPhaseCurrentStr) {
        //获取 A、b、c相电流
        BigDecimal a_phase_current = BigDecimal.valueOf(Double.valueOf(a_phase_current_str));
        BigDecimal b_phase_current = BigDecimal.valueOf(Double.valueOf(bPhaseCurrentStr));
        BigDecimal c_phase_current = BigDecimal.valueOf(Double.valueOf(cPhaseCurrentStr));
        BigDecimal age = a_phase_current.add(b_phase_current).add(c_phase_current).divide(new BigDecimal(3));
        //差值电压
        a_phase_current = a_phase_current.subtract(age);
        b_phase_current = b_phase_current.subtract(age);
        c_phase_current = c_phase_current.subtract(age);
        //获取差值Max
        a_phase_current = a_phase_current.compareTo(b_phase_current) == 1 ? a_phase_current : b_phase_current;
        a_phase_current = a_phase_current.compareTo(c_phase_current) == 1 ? a_phase_current : c_phase_current;
        //获取不平衡值
        BigDecimal phase_current = a_phase_current.divide(age, 2).multiply(new BigDecimal(100));
        return phase_current;
    }

    /***
     * 异步发送短信
     * @param alarmInfos
     */
    @Async
    public void sendSmsAndSaveAlarmNoticeHandler(ArrayList<DistributionCabinetAlarmInfo> alarmInfos){
        Set<Integer> collect = alarmInfos.stream().map(DistributionCabinetAlarmInfo::getCompanyId).collect(Collectors.toSet());
        List<AlarmPersonContact> alarmPersonContactList = distributionCompanyAlarmContactMidMapper.findAllAlarmContactInCompanyId(collect);
        if(alarmPersonContactList == null || alarmPersonContactList.size() <= 0){
            return;
        }
        //通过固定模板id 查询告警模板
        AlarmNoticeTemplet phoneTemplet = alarmNoticeTempletMapper.selectById(PHONETEMPLETID);
        //获得模板内容
        AlarmNoticeTemplet mailTemplet = alarmNoticeTempletMapper.selectById(EMAILTEMPLETID);
        //发送短信
        for (DistributionCabinetAlarmInfo alarmInfo : alarmInfos) {
            //短信
            sendSmsAndSaveAlarmNotice(alarmPersonContactList,alarmInfo,phoneTemplet);
            //邮件
            sendBankEmail(alarmPersonContactList,alarmInfo,mailTemplet);
        }
    }

    @Async
    public void sendBankEmail(List<AlarmPersonContact> alarmPersonContactList,DistributionCabinetAlarmInfo alarmInfo,AlarmNoticeTemplet mailTemplet) {
        if (com.baomidou.mybatisplus.core.toolkit.ObjectUtils.isEmpty(alarmPersonContactList)) {
            return;
        }
        for (AlarmPersonContact alarmPersonContact : alarmPersonContactList) {
            try {
                mimeMessageHelper.setTo(alarmPersonContact.getEmail());
                Template templet = this.createTemplate(mailTemplet.getName(), mailTemplet.getContent());
                String text = this.getBankEmaiBodyText(templet,alarmInfo);
                mimeMessageHelper.setText(text, true);
                mimeMessageHelper.setSentDate(new Date());
                MimeMessage message = mimeMessageHelper.getMimeMessage();
                javaMailSender.send(message);
            } catch (MessagingException e) {
                log.error("initial message  fail!",e);
            } catch (IOException e) {
                log.error("get templet   fail!",e);
            } catch (TemplateException e) {
                log.error("parse  templet   fail!",e);
            } catch (MailSendException e) {
                log.error("send  message   fail!",e);
            }
        }
    }

    /**
     * 发送短信
     * @param alarmPersonContactList
     */
    @Async
    public void sendSmsAndSaveAlarmNotice(List<AlarmPersonContact> alarmPersonContactList,DistributionCabinetAlarmInfo distributionCabinetAlarmInfo,AlarmNoticeTemplet phoneTemplet){
        if (com.baomidou.mybatisplus.core.toolkit.ObjectUtils.isEmpty(alarmPersonContactList)) {
            return;
        }
        for(AlarmPersonContact alarmPersonContact:alarmPersonContactList){
            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
            System.setProperty("sun.net.client.defaultReadTimeout", "10000");
            SendSmsRequest request = new SendSmsRequest();
            request.setPhoneNumbers(alarmPersonContact.getPhone());
            //短信模板和参数
            request.setTemplateCode(phoneTemplet.getContent());
            request.setSignName(signName);
            request.setTemplateParam(getParmJsonString(distributionCabinetAlarmInfo));
            SendSmsResponse sendSmsResponse=null;
            if (null == acsClient) {
                continue;
            }
            try {
                sendSmsResponse = acsClient.getAcsResponse(request);
            } catch (ClientException e) {
                log.error("配电负荷、不平衡度指标告警发送短信发生异常 ：" + e.getMessage());
                e.printStackTrace();
            }
            if (null != sendSmsResponse && !"OK".equalsIgnoreCase(sendSmsResponse.getCode())) {
                log.error("配电负荷、不平衡度指标告警发送短信发生异常:param："+JSONObject.toJSONString(request.getBodyParameters())+";error："+sendSmsResponse.getMessage());
            }
        }
    }

    static String getParmJsonString(DistributionCabinetAlarmInfo distributionCabinetAlarmInfo) {
        JSONObject param = new JSONObject();
        String areaPath = distributionCabinetAlarmInfo.getAreaPath();
        if(areaPath.contains(":")){
            areaPath = areaPath.replaceAll(":", "/");
        }
        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern(DateUtil.DATE_TIME_FORMAT_DEFAULT);
        param.put("areaPath", "【"+areaPath+"-"+distributionCabinetAlarmInfo.getRoomName()+"】");
        param.put("deviceType", "【"+distributionCabinetAlarmInfo.getCabinetName()+"】,【"+dtf2.format(distributionCabinetAlarmInfo.getAlarmTime())+"】");
        param.put("content", distributionCabinetAlarmInfo.getContent());
        return param.toString();
    }

    enum AlarmContent {
        load_up("负荷越上限", "负荷越上限，请关注！", 1),
        load_down("负荷越下限", "负荷越下限，请关注！", 2),
        aoib_voltage_up("电压三相不平衡", "电压三相不平衡超过?%，请关注！", 3),
        aoib_voltage_down("电压三相严重不平衡", "电压三相不平衡超过?%，请关注！", 4),
        aoib_current_up("电流三相不平衡", "电流三相不平衡超过?%，请关注！", 5),
        aoib_current_down("电流三相严重不平衡", "电流三相不平衡超过?%，请关注！", 6);

        private String name;
        private String content;
        private int type;

        AlarmContent(String name, String content, int type) {
            this.name = name;
            this.content = content;
            this.type = type;
        }

        /***
         * 通过 type 获取对象
         * @param type
         * @return
         */
        public static AlarmContent getAlarmContentByType(int type) {
            for (AlarmContent alarmContent : AlarmContent.values()) {
                if (alarmContent.type == type) {
                    return alarmContent;
                }
            }
            return null;
        }
    }

    /**
     * freeMaker通过字符串创建模板 freeMarkerConfiguration 中会加载freemaker模板
     */
    private Template createTemplate(String name, String templateContent) throws IOException {
        Template template = freemarkerConf.getTemplate(name, (Locale) null, (Object) null, "utf-8", true, true);
        if (template != null) {
            return template;
        }
        synchronized (this) {
            TemplateLoader templateLoader = freemarkerConf.getTemplateLoader();
            if (templateLoader != null && templateLoader instanceof StringTemplateLoader) {
                ((StringTemplateLoader) templateLoader).putTemplate(name, templateContent);
                freemarkerConf.setTemplateLoader(templateLoader);
            } else {
                StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
                stringTemplateLoader.putTemplate(name, templateContent);
                freemarkerConf.setTemplateLoader(stringTemplateLoader);
            }
            freemarkerConf.clearTemplateCache();
            template = freemarkerConf.getTemplate(name, "utf-8");
            return template;
        }
    }

    public  String getBankEmaiBodyText(Template  template,DistributionCabinetAlarmInfo distributionCabinetAlarmInfo) throws IOException, TemplateException {
        Map<String, String> param = new HashMap<String, String>();
        String areaPath = distributionCabinetAlarmInfo.getAreaPath();
        if(areaPath.contains(":")){
            areaPath = areaPath.replaceAll(":", "/");
        }
        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern(DateUtil.DATE_TIME_FORMAT_DEFAULT);
        param.put("areaPath", "【"+areaPath+"-"+distributionCabinetAlarmInfo.getRoomName()+"】");
        param.put("deviceType", "【"+distributionCabinetAlarmInfo.getCabinetName()+"】,【"+dtf2.format(distributionCabinetAlarmInfo.getAlarmTime())+"】");
        param.put("content", distributionCabinetAlarmInfo.getContent());

        StringWriter writer = new StringWriter();
        template.process(param, writer);
        return writer.toString();
    }
}
